<template>
  <div style="padding: 5px">
    <a-row :gutter="8">
      <a-col :span="6">
        <a-card>
          <template #title>
            <a-space>
              <span> {{ isJavaSource === 'java' ? 'Java Entity' : 'Typescript' }}</span>
              <a-switch
                @change="switchChange"
                v-model:checked="isJavaSource"
                checkedValue="java"
                unCheckedValue="ts"
                checked-children="开"
                un-checked-children="关"
              />
            </a-space>
          </template>
          <a-textarea v-model:value="value" :placeholder="`请输入${isJavaSource === 'java' ? 'Java代码' : 'Typescript代码'}`" style="height: 85vh" />
        </a-card>
      </a-col>
      <a-col :span="18">
        <a-card title="Typescript">
          <a-tabs v-model:activeKey="activeKey">
            <a-tab-pane key="1" tab="类型转换">
              <a-row :gutter="8">
                <a-col :span="12">
                  <a-card>
                    <template #title>
                      <a-space>
                        <span>Typescript Type</span>
                        <a-button @click="handleCopy('typeResult')" type="primary">复制</a-button>
                      </a-space>
                    </template>
                    <div style="max-height: 85vh; overflow: auto; font-size: 16px" id="typeResult">
                      export interface {{ className !== null ? className[1] : '' }} {
                      <div v-for="(item, index) in resultValue" :key="index">
                        {{ item.split(' ')[2] }}: {{ getTsTypeByJavaType(item.split(' ')[1]) || item.split(' ')[1] }};
                      </div>
                      }
                    </div>
                  </a-card>
                </a-col>
                <a-col :span="12">
                  <a-card>
                    <template #title>
                      <a-space>
                        <span>Typescript Value</span>
                        <a-button @click="handleCopy('valueResult')" type="primary">复制</a-button>
                      </a-space>
                    </template>
                    <div style="max-height: 85vh; overflow: auto; font-size: 16px" id="valueResult">
                      <div v-for="(item, index) in resultValue" :key="index">
                        <span>{{ item.split(' ')[2] }}: {{ getValueByType(typeMap[item.split(' ')[1]] || item.split(' ')[1]) }},</span>
                      </div>
                    </div>
                  </a-card>
                </a-col>
              </a-row>
            </a-tab-pane>
            <a-tab-pane key="2" tab="模拟数据" forceRender>
              <a-row :gutter="8">
                <a-col :span="24">
                  <a-card>
                    <template #title>
                      <a-space>
                        <span>Mock数据</span>
                        <a-input-number addon-before="生成条数" v-model:value="dataNumber" :min="1" :max="50" @change="mockGen()" />
                        <a-button @click="handleCopy('mockResult')" type="primary">复制</a-button>
                      </a-space>
                    </template>
                    <div style="display: none" id="mockResult">{{ mockData }}</div>
                    <VueJsonPretty showLineNumber :data="mockData" />
                  </a-card>
                </a-col>
              </a-row>
            </a-tab-pane>
            <a-tab-pane key="3" tab="Sql数据" forceRender>
              <a-row :gutter="8">
                <a-col :span="24">
                  <a-card>
                    <template #title>
                      <a-space>
                        <span>Sql数据</span>
                        <a-input-number addon-before="生成条数" v-model:value="dataNumber" :min="1" :max="50" @change="mockGen()" />
                        <a-input style="width: 500px" addon-before="表名" v-model:value="tableName" @change="mockGen()" />
                        <a-button @click="handleCopy('sqlDataResult')" type="primary">复制</a-button>
                      </a-space>
                    </template>
                    <div id="sqlDataResult">
                      <div style="width: 100%; word-break: break-all; margin-top: 5px" v-for="(item, index) in sqlData" :key="index">
                        {{ item }}
                      </div>
                    </div>
                  </a-card>
                </a-col>
              </a-row>
            </a-tab-pane>
          </a-tabs>
        </a-card>
      </a-col>
    </a-row>
  </div>
</template>

<script setup lang="ts">
  import VueJsonPretty from 'vue-json-pretty'
  import 'vue-json-pretty/lib/styles.css'
  // @ts-ignore
  import Mock from 'mockjs'
  import type { Ref } from 'vue'
  import { ref, watch } from 'vue'
  import { message } from 'ant-design-vue'

  const activeKey = ref('1')

  const value: Ref = ref<string>('')
  const resultValue: Ref = ref<string[]>([])
  const className: Ref = ref<string[]>([])

  const mockData = ref({})
  const dataNumber = ref(1)
  const sqlData = ref<string[]>([])
  const tableName = ref('表名')
  const isJavaSource = ref('java')

  const typeMap: Record<string, string> = {
    String: 'string',
    string: 'string',
    number: 'number',
    int: 'number',
    Integer: 'number',
    BigDecimal: 'number',
    boolean: 'boolean'
  }

  watch(value, () => {
    if (isJavaSource.value === 'java') {
      const pattern = /private\s+([A-Z][<|>|\w]+)\s+\w+/gm
      const matches = value.value.match(pattern)
      const classNamePattern = /(?:class)\s+(\w+)\s+/gm
      const classNameMatches = classNamePattern.exec(value.value)
      className.value = classNameMatches
      resultValue.value = matches
      if (classNameMatches) {
        tableName.value = camelToSnakeCase(classNameMatches[1])
      }
    } else {
      const pattern = /\s?(\w+)\s?:\s+(\w+)/gm
      const matches = value.value.match(pattern)
      const result: string[] = []
      matches.forEach((item: string) => {
        const val = pattern.exec(item)
        if (val) {
          result.push(`private ${val[2]} ${val[1]}`)
        }
      })
      resultValue.value = result
    }
    mockGen()
  })

  init()

  // 切换java/ts
  function switchChange(v: string) {
    localStorage.setItem('isJavaSource', v)
  }

  // 初始化
  function init() {
    const isJavaSourceVal = localStorage.getItem('isJavaSource')
    if (isJavaSourceVal) {
      isJavaSource.value = isJavaSourceVal
    }
  }

  // 驼峰转下划线
  function camelToSnakeCase(str: string) {
    const snakeStr = str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
    return snakeStr.charAt(0) === '_' ? snakeStr.substring(1) : snakeStr
  }

  // 生成模拟数据
  function mockGen() {
    if (!resultValue.value || resultValue.value.length === 0) {
      return
    }
    interface Obj {
      [key: string]: number
    }
    const key = `list`
    const arr = []
    const sqlArr = []
    for (let index = 0; index < dataNumber.value; index++) {
      const obj: Obj = {}
      const sql = 'INSERT INTO ' + tableName.value + " (`field`) VALUES ('values');"
      const fieldArr = []
      const valuesArr = []
      for (let item in resultValue.value) {
        const data: string = resultValue.value[item]
        const val = mockDataByType(getTsTypeByJavaType(data.split(' ')[1]) || data.split(' ')[1], data.split(' ')[2])
        obj[data.split(' ')[2]] = val
        fieldArr.push(camelToSnakeCase(data.split(' ')[2]))
        valuesArr.push(val)
      }
      arr.push(obj)
      sqlArr.push(sql.replace('field', fieldArr.join('`,`')).replace('values', valuesArr.join("','")))
    }
    sqlData.value = sqlArr
    mockData.value = Mock.mock({
      [key]: arr
    })
  }

  // 生成mock数据
  function mockDataByType(type: string, field: string) {
    if (field === 'id') {
      return Mock.Random.integer(10000000, 99999999)
    } else if (field === 'tenantId') {
      return 0
    }
    if (field.includes('Id')) {
      return field
    }
    switch (type) {
      case 'number':
        return Mock.Random.integer(100000, 999999)
      case 'string':
        return Mock.Random.ctitle()
      case 'boolean':
        return true
      case 'Date':
        return Mock.Random.date('yyyy-MM-dd HH:mm:ss')
      default:
        return null
    }
  }

  // 复制内容到剪贴板
  function handleCopy(id: string) {
    const input = document.createElement('input')
    input.value = document.getElementById(id)?.innerText as string
    document.body.appendChild(input)
    input.select()
    document.execCommand('copy')
    document.body.removeChild(input)
    message.success('复制成功')
  }

  // 通过类型获取默认值
  function getValueByType(type: any) {
    switch (type) {
      case 'number':
        return 0
      case 'string':
        return "''"
      case 'boolean':
        return 'true'
      default:
        return 'null'
    }
  }

  // java类型转ts类型
  function getTsTypeByJavaType(type: string) {
    const startsWithArr = ['List', 'Set']
    if (startsWithArr.filter((item) => type.startsWith(item)).length > 0) {
      const pattern = /<([A-Z]\w+)>/gm
      const group: RegExpExecArray | null = pattern.exec(type)
      return group ? `${group[1]}[]` : ''
    }
    return typeMap[type]
  }
</script>

<style scoped></style>
